﻿using System;
using System.Threading.Tasks;

namespace Beeflys
{
    sealed class EntityRef : AActorRef, IEntityRef
    {
        public EntityRef(AActor actor, ActorId id) : base(actor, id)
        {
        }

        private ActorStartNotify actorStartNotify = new ActorStartNotify();

        public async Task<IActorRef> AddChildAsync<TActor>(string name)
            where TActor : AActor
        {
            var actorRef = await this.AddChildAsync<TActor>(ActorId.DEFAULT_HOST, name);
            await actorStartNotify.InvokStartNotifyAsync(actorRef);
            return actorRef;
        }

        public async Task<IActorRef> AddChildAsync<TActor, T1>(string name,
            T1 item1)
            where TActor : AActor, new()
        {
            var actorRef = await this.AddChildAsync<TActor>(ActorId.DEFAULT_HOST, name);
            await actorStartNotify.InvokStartNotifyAsync(actorRef, item1);
            return actorRef;
        }

        public async Task<IActorRef> AddChildAsync<TActor, T1, T2>(string name,
            T1 item1, T2 item2)
            where TActor : AActor, new()
        {
            var actorRef = await this.AddChildAsync<TActor>(ActorId.DEFAULT_HOST, name);
            await actorStartNotify.InvokStartNotifyAsync(actorRef, item1, item2);
            return actorRef;
        }

        public async Task<IActorRef> AddChildAsync<TActor, T1, T2, T3>(string name,
            T1 item1, T2 item2, T3 item3)
            where TActor : AActor, new()
        {
            var actorRef = await this.AddChildAsync<TActor>(ActorId.DEFAULT_HOST, name);
            await actorStartNotify.InvokStartNotifyAsync(actorRef, item1, item2, item3);
            return actorRef;
        }

        public async Task<IActorRef> AddChildAsync<TActor, T1, T2, T3, T4>(string name,
            T1 item1, T2 item2, T3 item3, T4 item4)
            where TActor : AActor, new()
        {
            var actorRef = await this.AddChildAsync<TActor>(ActorId.DEFAULT_HOST, name);
            await actorStartNotify.InvokStartNotifyAsync(actorRef, item1, item2, item3, item4);
            return actorRef;
        }

        public async Task<IActorRef> AddChildAsync<TActor, T1, T2, T3, T4, T5>(string name,
            T1 item1, T2 item2, T3 item3, T4 item4, T5 item5)
            where TActor : AActor, new()
        {
            var actorRef = await this.AddChildAsync<TActor>(ActorId.DEFAULT_HOST, name);
            await actorStartNotify.InvokStartNotifyAsync(actorRef, item1, item2, item3, item4, item5);
            return actorRef;
        }

        public async Task<IActorRef> AddChildAsync<TActor, T1, T2, T3, T4, T5, T6>(string name,
            T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6)
            where TActor : AActor, new()
        {
            var actorRef = await this.AddChildAsync<TActor>(ActorId.DEFAULT_HOST, name);
            await actorStartNotify.InvokStartNotifyAsync(actorRef, item1, item2, item3, item4, item5, item6);
            return actorRef;
        }

        public async Task<IActorRef> AddChildAsync<TActor, T1, T2, T3, T4, T5, T6, T7>(string name,
            T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7)
            where TActor : AActor, new()
        {
            var actorRef = await this.AddChildAsync<TActor>(ActorId.DEFAULT_HOST, name);
            await actorStartNotify.InvokStartNotifyAsync(actorRef, item1, item2, item3, item4, item5, item6, item7);
            return actorRef;
        }

        public async Task<IActorRef> AddChildAsync<TActor>(string host, string name) where TActor : AActor
        {
            var request = new AddChildren();
            request.Host = host;
            request.ActorName = name;
            request.ActorType = typeof(TActor);

            var result = await this.CallAsync<IActorRef>(request, TimeSpan.Zero, null);
            if(result.ActorOpencode == ActorOpencode.SUCCEED)
            {
                return result.Response;
            }

            return null;
        }

        public async Task<IActorRef> GetChildAsync(string name)
        {
            var request = new GetChildren();
            request.ActorName = name;

            var result = await this.CallAsync<IActorRef>(request, TimeSpan.Zero, null);

            if(result.ActorOpencode == ActorOpencode.SUCCEED)
            {
                return result.Response;
            }

            return null;
        }

        public async Task<bool> DestroyChildAsync(string name)
        {
            var request = new DelChildren();
            request.ActorName = name;

            var result = await this.CallAsync<bool>(request, TimeSpan.Zero, null);

            if(result.ActorOpencode == ActorOpencode.SUCCEED)
            {
                return result.Response;
            }

            return false;
        }

       
    }
}